﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Text.RegularExpressions;

namespace TextLineUpdate
{
    /// <summary>
    /// 行編集
    /// </summary>
    public partial class TextLineUpdate : Form
    {
        #region 定数
        //CopyStringのMaxLength
        private int COPY_STRING_MAX_LENGTH = 60000000;
        #endregion

        #region 変数
        Utility utility;
        FileIO fileIO;
        //ファイル読み込みフラグ
        bool isDragFile;
        #endregion

        #region メソッド
        
        /// <summary>
        /// コンストラクタ
        /// </summary>
        public TextLineUpdate()
        {
            InitializeComponent();
            //中央表示
            StartPosition = FormStartPosition.CenterScreen;
            this.utility = new Utility();
            this.fileIO = new FileIO();
        }


        /// 半角数値チェック
        /// <summary>
        /// 入力された値が半角数値かどうか判断します。
        /// </summary>
        /// <param name="inStr">対象文字列</param>
        /// <returns></returns>
        public bool IsHalfNumber(String inStr)
        {
            if (String.IsNullOrEmpty(inStr))
            {
                return true;
            }
            else
            {
                Regex regex = new Regex(@"^[0-9]+$");
                return regex.IsMatch(inStr);
            }
        }

        /// 文字列のバイト数を取得
        /// <summary>
        /// 文字列のバイト数を取得
        /// </summary>
        /// メソッド名が長いため作成
        /// <param name="inputString">入力文字列</param>
        private int GetByteCount(string inputString)
        {
            int lengthByte = 0;
            lengthByte = Encoding.GetEncoding("shift-jis").GetByteCount(inputString);
            return lengthByte;
        }

        /// <summary>
        /// 編集後文字数がMaxLengthを超えないかチェック
        /// </summary>
        /// <param name="isNotNullStart"></param>
        /// <param name="isNotNullEnd"></param>
        private bool CheckAddedString(bool isNullStart, bool isNullEnd, int longByte, int arrayLength)
        {
            //開始が未入力の場合
            if (isNullStart)
            {
                if (COPY_STRING_MAX_LENGTH < arrayLength * (longByte + 1 + this.GetByteCount(this.textBoxLineAddEnd.Text)))
                {
                    return false;
                }
            }
            //終了が未入力の場合
            else if (isNullEnd)
            {
                if (COPY_STRING_MAX_LENGTH < arrayLength * (this.GetByteCount(this.textBoxLineAddStart.Text) + 1 + longByte))
                {
                    return false;
                }
            }
            //両方入力がある場合
            else
            {
                if (COPY_STRING_MAX_LENGTH < arrayLength * (this.GetByteCount(this.textBoxLineAddStart.Text) + 1 + longByte + 1 + this.GetByteCount(this.textBoxLineAddEnd.Text)))
                {
                    return false;
                }
            }
            return true;
        }


        /// 行追加後を作成
        /// <summary>
        /// 行追加後を作成
        /// </summary>
        /// <param name="dispString">表示文字列</param>
        /// <param name="longByte">最も長い行のバイト数</param>
        /// <param name="stringArray">行単位で格納した文字配列</param>
        /// <returns></returns>
        private bool AddedString(StringBuilder dispString,int longByte,string[] stringArray)
        {
            //行追加削除開始が未入力の場合
            if (String.IsNullOrEmpty(this.textBoxLineAddStart.Text))
            {
                //編集後にMaxLengthを超えないかチェック
                if (!this.CheckAddedString(true, false, longByte, stringArray.Length))
                {
                    return false;
                }
                //行に連結する
                for (int i = 0; i < stringArray.Length; i++)
                {
                    //行に文字列があり、空白だけでない場合
                    if (!String.IsNullOrEmpty(stringArray[i])
                        && !String.IsNullOrEmpty(stringArray[i].Replace(" ", "")))
                    {
                        //StringBuilderで連結するよう修正
                        dispString.Append(stringArray[i]);
                        if (String.IsNullOrEmpty(this.textBoxSpaceCount.Text))
                        {
                            dispString.Append(this.utility.SpaceText(longByte - this.GetByteCount(stringArray[i]), ""));
                        }
                        else
                        {
                            dispString.Append(this.utility.SpaceText(Int32.Parse(this.textBoxSpaceCount.Text), ""));
                        }

                        //dispString.Append(" ");
                        dispString.Append(this.textBoxLineAddEnd.Text);
                        dispString.AppendLine("");
                    }
                    else
                    {
                        dispString.AppendLine(stringArray[i]);
                    }
                }
            }
            //行追加削除終了が未入力の場合
            else if (String.IsNullOrEmpty(this.textBoxLineAddEnd.Text))
            {
                //編集後にMaxLengthを超えないかチェック
                if (!this.CheckAddedString(false, true, longByte, stringArray.Length))
                {
                    return false;
                }
                //行に連結する
                for (int i = 0; i < stringArray.Length; i++)
                {
                    //行に文字列があり、空白だけでない場合
                    if (!String.IsNullOrEmpty(stringArray[i])
                        && !String.IsNullOrEmpty(stringArray[i].Replace(" ", "")))
                    {
                        //StringBuilderで連結するよう修正
                        dispString.Append(this.textBoxLineAddStart.Text);
                        //dispString.Append(" ");
                        dispString.Append(stringArray[i]);
                        dispString.AppendLine("");
                    }
                    else
                    {
                        dispString.AppendLine(stringArray[i]);
                    }
                }
            }
            //行追加削除が未入力でない場合
            else
            {
                //編集後にMaxLengthを超えないかチェック
                if (!this.CheckAddedString(false, false, longByte, stringArray.Length))
                {
                    return false;
                }
                //行に連結する
                for (int i = 0; i < stringArray.Length; i++)
                {
                    //行に文字列があり、空白だけでない場合
                    if (!String.IsNullOrEmpty(stringArray[i])
                        && !String.IsNullOrEmpty(stringArray[i].Replace(" ", "")))
                    {
                        //StringBuilderで連結するよう修正
                        dispString.Append(this.textBoxLineAddStart.Text);
                        //dispString.Append(" ");
                        dispString.Append(stringArray[i]);
                        if (String.IsNullOrEmpty(this.textBoxSpaceCount.Text))
                        {
                            dispString.Append(this.utility.SpaceText(longByte - this.GetByteCount(stringArray[i]), ""));
                        }
                        else
                        {
                            dispString.Append(this.utility.SpaceText(Int32.Parse(this.textBoxSpaceCount.Text), ""));
                        }

                        //dispString.Append(" ");
                        dispString.Append(this.textBoxLineAddEnd.Text);
                        dispString.AppendLine("");

                    }
                    else
                    {
                        dispString.AppendLine(stringArray[i]);
                    }
                }
            }
            return true;
        }

        /// 行削除後を作成
        /// <summary>
        /// 行削除後を作成
        /// </summary>
        /// <param name="dispString">表示文字列</param>
        /// <param name="stringArray">行単位で格納した文字配列</param>
        private void DeletedString(StringBuilder dispString, string[] stringArray)
        {
            int countStart;
            int countEnd;
            int lengthStart;
            int lengthEnd;

            //両方入力がある時
            if (!String.IsNullOrEmpty(this.textBoxLineAddStart.Text)
                && !String.IsNullOrEmpty(this.textBoxLineAddEnd.Text))
            {
                lengthStart = this.textBoxLineAddStart.Text.Length;
                lengthEnd = this.textBoxLineAddEnd.Text.Length;
                for (int i = 0; i < stringArray.Length; i++)
                {
                    countStart = stringArray[i].IndexOf(this.textBoxLineAddStart.Text);
                    //文字列があった場合(0以上)
                    if (countStart >= 0)
                    {
                        stringArray[i] = stringArray[i].Remove(countStart, lengthStart);
                    }
                    countEnd = stringArray[i].LastIndexOf(this.textBoxLineAddEnd.Text);
                    //文字列があった場合(0より大きい)
                    if (countEnd > 0)
                    {
                        stringArray[i] = stringArray[i].Remove(countEnd, lengthEnd);
                    }
                }
            }
            //開始の入力があるとき
            else if (!String.IsNullOrEmpty(this.textBoxLineAddStart.Text))
            {
                lengthStart = this.textBoxLineAddStart.Text.Length;
                for (int i = 0; i < stringArray.Length; i++)
                {
                    countStart = stringArray[i].IndexOf(this.textBoxLineAddStart.Text);
                    //文字列があった場合(0以上)
                    if (countStart >= 0)
                    {
                        stringArray[i] = stringArray[i].Remove(countStart, lengthStart);
                    }
                }
            }
            //終了が未入力でない時（両方ないことはない）
            else
            {
                lengthEnd = this.textBoxLineAddEnd.Text.Length;
                for (int i = 0; i < stringArray.Length; i++)
                {
                    countEnd = stringArray[i].LastIndexOf(this.textBoxLineAddEnd.Text);
                    //文字列があった場合(0より大きい)
                    if (countEnd > 0)
                    {
                        stringArray[i] = stringArray[i].Remove(countEnd, lengthEnd);
                    }
                }
            }

            //行を連結する
            for (int i = 0; i < stringArray.Length; i++)
            {
                dispString.AppendLine(stringArray[i].TrimEnd(null));
            }
        }

        /// <summary>
        /// 文字列を改行毎に配列に格納する
        /// </summary>
        /// <param name="allText"></param>
        /// <returns></returns>
        private string[] SplitBreak(string allText)
        {
            //改行コードで区切る用
            string[] breakWord = new string[1];
            breakWord[0] = "\r\n";
            //改行ごとに区切って配列に格納する
            string[] allTextArray = allText.Split(breakWord, StringSplitOptions.None);

            for (int i = 0; i < allTextArray.Length; i++)
            {
                allTextArray[i] = allTextArray[i].TrimEnd(null);
            }

            return allTextArray;
        }

        /// <summary>
        /// 文字列のスペースを変換する
        /// </summary>
     　 /// 全角スペースとタブスペースを半角スペースに変換
        /// <param name="allText"></param>
        /// <returns>変換後の文字列</returns>
        private string SpaceReplace(string allText)
        {
            //全角スペースを半角スペース2つに変換
            allText = allText.Replace("　", "  ");
            //タブスペースを半角スペース4つに変換
            allText = allText.Replace("\t", "    ");
            

            return allText;
        }


        #endregion

        #region イベント

        /// <summary>
        /// 行追加_CheckedChanged
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void radioButtonLineAdd_CheckedChanged(object sender, EventArgs e)
        {
            if (this.radioButtonLineAdd.Checked)
            {
                this.labelAddDeleteStart.Text = "+";
                this.labelAddDeleteEnd.Text = "+";
            }
            else
            {
                this.labelAddDeleteStart.Text = "-";
                this.labelAddDeleteEnd.Text = "-";
            }

        }

        /// <summary>
        /// フォーム_KeyDown
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TextLineUpdate_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode != Keys.Shift && e.KeyCode != Keys.Alt)
            {
                if (e.KeyCode == Keys.Enter)
                {
                    if (this.ActiveControl == this.textBoxAllText)
                    {
                        return;
                    }

                    this.SelectNextControl(this.ActiveControl, true, true, false, false);
                    e.Handled = true;
                }
            }
            //全選択のショートカットキーが押された場合
            if (e.Control && e.KeyCode == Keys.A)
            {
                //AllTextにフォーカスがある場合
                if (this.ActiveControl == this.textBoxAllText)
                {
                    //全選択する
                    this.textBoxAllText.SelectAll();
                }
            }
        }
        
        /// <summary>
        /// フォーム_Load
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TextLineUpdate_Load(object sender, EventArgs e)
        {
            //未実装のため消す
            this.labelGyo.Visible = false;
            this.textBoxGyo.Visible = false;
            this.labelByte.Visible = false;
            this.textBoxByte.Visible = false;
        }

        /// <summary>
        /// フォーム_Shown
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TextLineUpdate_Shown(object sender, EventArgs e)
        {
            //行追加削除開始にフォーカスを移動
            this.textBoxLineAddStart.Focus();
        }

        /// <summary>
        /// 実行ボタン_Click
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonJikko_Click(object sender, EventArgs e)
        {
            try
            {
                //カーソルを砂時計にする
                this.Cursor = Cursors.WaitCursor;
                //テキストの文字列を格納
                string allText = this.textBoxAllText.Text;

                //カンマで改行を行う場合
                if (this.checkBoxIsCommaBreak.Checked)
                {
                    //カンマ前が選択された場合
                    if (this.radioButtonFrontBreak.Checked)
                    {
                        allText = allText.Replace(",", "\r\n,");
                    }
                    //カンマ後が選択された場合
                    else
                    {
                        allText = allText.Replace(",", ",\r\n");
                    }
                }

                //行追加削除を行う場合
                if (this.checkBoxIsLineAddDelete.Checked)
                {
                    //行追加削除するテキストのどちらかが未入力でない場合
                    if (!String.IsNullOrEmpty(this.textBoxLineAddStart.Text)
                        || !String.IsNullOrEmpty(this.textBoxLineAddEnd.Text))
                    {
                        //全角スペース、タブスペースを半角スペースに変換
                        allText = this.SpaceReplace(allText);
                        //改行ごとに区切って配列に格納する
                        string[] allTextArray = this.SplitBreak(allText);

                        //編集されたテキストを格納用
                        StringBuilder lineUpdate = new StringBuilder();

                        //行に追加が選択された場合
                        if (this.radioButtonLineAdd.Checked)
                        {

                            int longByte = 0;
                            //最も長い行のバイト数を計算
                            for (int i = 0; i < allTextArray.Length; i++)
                            {
                                if (longByte < this.GetByteCount(allTextArray[i]))
                                {
                                    longByte = this.GetByteCount(allTextArray[i]);
                                }
                            }
                            //追加後の文字列を作成
                            if (!this.AddedString(lineUpdate, longByte, allTextArray))
                            {
                                MessageBox.Show("最大入力文字数を超えました。\r\n編集前のテキストを分けて実行してください。", "警告");
                                return;
                            }
                        }
                        //行から削除が選択された場合
                        else
                        {
                            //削除後の文字列を作成
                            this.DeletedString(lineUpdate, allTextArray);
                        }
                        //編集後の文字列を格納
                        allText = lineUpdate.ToString();
                    }
                }

                if (!String.IsNullOrEmpty(allText))
                {
                    using (CopyString CS = new CopyString())
                    {
                        if (CS.TextMaxLength < allText.Length)
                        {
                            MessageBox.Show("最大入力文字数を超えました。\r\n編集前のテキストを分けて実行してください。", "警告");
                            return;
                        }
                        CS.CopyAllString = allText;
                        CS.ShowDialog();
                    }
                }
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message　+"\r\n上手くいきませんでした。もう一度お願いします。","エラーが発生しました。");
            }
            finally
            {
                //カーソルを元に戻す
                this.Cursor = Cursors.Default;
            }
        }

        /// <summary>
        /// 閉じるボタン
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        /// 全テキスト_DragEnter
        /// <summary>
        /// 全テキスト_DragEnter
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void textBoxAllText_DragEnter(object sender, DragEventArgs e)
        {
            try
            {
                //カーソルを砂時計にする
                this.Cursor = Cursors.WaitCursor;
                //ドラッグしてファイル読み込み
                this.isDragFile = true;
                string tempString;
                //ドラッグされたファイルのパスを取得
                string[] filePath = (string[])e.Data.GetData(DataFormats.FileDrop);
                //ファイルを読み込みテキストを格納
                tempString = this.fileIO.ReadText(filePath[0]);
                //MaxLengthを超えていないかチェック
                if (tempString.Length > this.textBoxAllText.MaxLength)
                {
                    //超えたところから取り除く
                    tempString = tempString.Remove(this.textBoxAllText.MaxLength);
                    this.textBoxAllText.Text = "";
                    //ファイルを読み込みテキストに表示
                    this.textBoxAllText.Text = tempString;
                    MessageBox.Show("最大入力文字数を超えました。\r\n超えた文字列は取り除かれます。", "警告");
                    return;
                }
                else
                {
                    //ファイルを読み込みテキストに表示
                    this.textBoxAllText.Text = tempString;
                }
            }
            finally
            {
                //初期値に戻す
                this.isDragFile = false;
                //カーソルを元に戻す
                this.Cursor = Cursors.Default;
            }
        }

        /// <summary>
        /// 全テキスト_TextChanged
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void textBoxAllText_TextChanged(object sender, EventArgs e)
        {
            //MaxLengthを超えていないかチェック
            if (this.textBoxAllText.TextLength >= this.textBoxAllText.MaxLength && !isDragFile)
            {
                MessageBox.Show("最大入力文字数を超えました。\r\nコピー＆ペーストの場合、超えた文字列は取り除かれます。", "警告");
            }
        }

        /// スペース数指定_TextChanged
        /// <summary>
        /// スペース数指定_TextChanged
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void textBoxSpaceCount_TextChanged(object sender, EventArgs e)
        {
            if (sender != null)
            {
                TextBox textControl = (TextBox)sender;

                //編集用の文字列にテキストの値をセット
                string editstr = textControl.Text;
                //選択されているテキストの開始点の確保用
                int intSelectionStart;
                //変更後のテキストの文字数を確保
                int intStrLength = textControl.Text.Length;

                //変更後の文字列が半角数字でない時
                if (!this.IsHalfNumber(textControl.Text))
                {
                    int i;
                    //半角数字でないものを検索して削除
                    for (i = intStrLength; i > 0; i--)
                    {
                        if (!this.IsHalfNumber(textControl.Text.Substring(i - 1, 1)))
                        {
                            editstr = editstr.Remove(i - 1, 1);
                        }
                    }

                    //カーソルの位置を取得
                    intSelectionStart = textControl.SelectionStart - 1;
                    //編集後の文字をテキストにセット
                    textControl.Text = editstr;
                    //カーソルの位置を設定
                    textControl.SelectionStart = intSelectionStart;
                }
            }
        }

        #endregion
    }
}